#include "app_buffer.h"
#include <stdlib.h>
#include "log/log.h"
#include <string.h>

/**
 * @brief 初始化子缓冲区
 *
 * @param size 子缓冲区大小
 * @return SubBuffer* 子缓冲区指针
 */
static SubBuffer *app_buffer_sub_buffer_init(int size)
{
    SubBuffer *sub_buffer = (SubBuffer *)malloc(sizeof(SubBuffer));
    sub_buffer->buffer = (char *)malloc(size);
    sub_buffer->len = 0;
    sub_buffer->size = size;

    return sub_buffer;
}

/**
 * @brief 初始化缓冲区
 *
 * @param size 子缓冲区大小
 * @return Buffer* 缓冲区指针
 */
Buffer *app_buffer_init(int size)
{
    Buffer *buffer = (Buffer *)malloc(sizeof(Buffer));
    if (buffer == NULL)
    {
        log_error("申请缓冲区结构体内存失败");
        free(buffer);
        return NULL;
    }

    buffer->write_index = 1;
    buffer->read_index = 0;

    buffer->sub_buffers[0] = app_buffer_sub_buffer_init(size);
    buffer->sub_buffers[1] = app_buffer_sub_buffer_init(size);

    if (buffer->sub_buffers[0] == NULL)
    {
        log_error("申请子缓冲区0结构体内存失败");
        free(buffer->sub_buffers[0]);
        free(buffer);
        return NULL;
    }

    if (buffer->sub_buffers[1] == NULL)
    {
        log_error("申请子缓冲区1结构体内存失败");
        free(buffer->sub_buffers[0]);
        free(buffer);
        return NULL;
    }

    if (buffer->sub_buffers[0]->buffer == NULL)
    {
        log_error("申请子缓冲区0内存失败");
        free(buffer->sub_buffers[0]->buffer);
        free(buffer->sub_buffers[1]);
        free(buffer->sub_buffers[0]);
        free(buffer);
        return NULL;
    }

    if (buffer->sub_buffers[1]->buffer == NULL)
    {
        log_error("申请子缓冲区1内存失败");
        free(buffer->sub_buffers[1]->buffer);
        free(buffer->sub_buffers[0]->buffer);
        free(buffer->sub_buffers[1]);
        free(buffer->sub_buffers[0]);
        free(buffer);
        return NULL;
    }

    pthread_mutex_init(&buffer->read_lock, NULL);
    pthread_mutex_init(&buffer->write_lock, NULL);

    return buffer;
}

/**
 * @brief 释放缓冲区
 *
 * @param buffer 缓冲区指针
 */
void app_buffer_free(Buffer *buffer)
{
    free(buffer->sub_buffers[0]->buffer);
    free(buffer->sub_buffers[1]->buffer);
    free(buffer->sub_buffers[1]);
    free(buffer->sub_buffers[0]);
    free(buffer);
}

/**
 * @brief 切换读写缓存区
 *
 * @param buffer 缓冲区指针
 * @param rw 读写标志，0表示读，1表示写
 */
static void app_buffer_swap_sub_buffer(Buffer *buffer, bool rw)
{
    if (rw == 0)
    {
        // 加写锁；目的：防止读缓存区切换到写缓存区时，写缓存区正在被写，导致读错误；
        log_debug("读取数据，切换读写缓存区前，加写锁");
        pthread_mutex_lock(&buffer->write_lock);

        int temp = buffer->read_index;
        buffer->read_index = buffer->write_index;
        buffer->write_index = temp;

        // 解写锁
        log_debug("读取数据，切换读写缓存区后，解写锁");
        pthread_mutex_unlock(&buffer->write_lock);
    }
    else if (rw == 1)
    {
        // 加读锁;目的：防止写缓存区切换到读缓存区时，读缓存区正在被读，导致写错误；
        log_debug("写入数据，切换读写缓存区前，加读锁");
        pthread_mutex_lock(&buffer->read_lock);

        int temp = buffer->read_index;
        buffer->read_index = buffer->write_index;
        buffer->write_index = temp;

        // 解读锁
        log_debug("写入数据，切换读写缓存区后，解读锁");
        pthread_mutex_unlock(&buffer->read_lock);
    }
}

/**
 * @brief 向缓冲区写入数据
 *
 * @param buffer 缓冲区指针
 * @param data 待写入的数据
 * @param len 待写入的数据长度
 * @return int 判断写入是否成功，成功返回0，失败返回-1
 */
int app_buffer_write(Buffer *buffer, char *data, int len)
{
    // 判断数据长度是否超过255字节
    if (len > 255)
    {
        log_error("写入数据长度超过255字节");
        return -1;
    }

    // 加写锁；目的：防止多线程同时写入数据，导致数据错乱；（竞态条件）
    log_debug("写入数据前，加写锁");
    pthread_mutex_lock(&buffer->write_lock);

    // 获取写缓存区
    SubBuffer *write_buffer = buffer->sub_buffers[buffer->write_index];

    // 判断写缓存区是否已满
    if (write_buffer->len + len + 1 > write_buffer->size)
    {
        // 如果写缓存区已满，则切换写缓存区
        app_buffer_swap_sub_buffer(buffer,1);
        write_buffer = buffer->sub_buffers[buffer->write_index];
        if (write_buffer->len + len + 1 > write_buffer->size)
        {
            log_error("写缓存区已满");
            // 解写锁
            pthread_mutex_unlock(&buffer->write_lock);
            return -1;
        }
    }

    // 先写数据长度，再写数据
    write_buffer->buffer[write_buffer->len] = len;
    memcpy(write_buffer->buffer + write_buffer->len + 1, data, len);

    // 更新写缓存区长度
    write_buffer->len += len + 1;

    // 解写锁
    log_debug("写入数据后，解写锁");
    pthread_mutex_unlock(&buffer->write_lock);

    return 0;
}

/**
 * @brief 从缓冲区读取数据
 *
 * @param buffer 缓冲区指针
 * @param data 读取到的数据
 * @param size 读取数据容器大小
 * @return int 读取到的数据长度
 */
int app_buffer_read(Buffer *buffer, char *data, int size)
{
    // 加读锁；目的：防止多线程同时读取数据，导致数据错乱；（竞态条件）
    log_debug("读取数据前，加读锁");
    pthread_mutex_lock(&buffer->read_lock);

    // 获取读缓存区
    SubBuffer *read_buffer = buffer->sub_buffers[buffer->read_index];

    // 判断读缓存区是否为空
    if (read_buffer->len == 0)
    {
        app_buffer_swap_sub_buffer(buffer,0);
        read_buffer = buffer->sub_buffers[buffer->read_index];
        if (read_buffer->len == 0)
        {
            log_error("读缓存区为空");
            return -1;
        }
    }

    // 先读数据长度，再读数据
    int len = read_buffer->buffer[0];
    if (len > size)
    {
        log_error("读取数据长度超过容器大小");
        // 解读锁
        pthread_mutex_unlock(&buffer->read_lock);
        return -1;
    }

    // 读取数据长度后的数据
    memcpy(data, read_buffer->buffer + 1, len);

    // 将后面未读取的数据移动到读缓存区开头
    memmove(read_buffer->buffer, read_buffer->buffer + len + 1, read_buffer->len - len - 1);

    // 更新读缓存区长度
    read_buffer->len -= len + 1;

    // 解读锁
    log_debug("读取数据后，解读锁");
    pthread_mutex_unlock(&buffer->read_lock);

    return len;
}
